// copyright 1993 Michael B. Johnson; some portions copyright 1994, MIT
// see COPYRIGHT for reuse legalities
//

#import "RIBTranslate.h"

@implementation RIBTranslate

+ initialize { return [RIBTranslate setVersion:1], self; }

- init
{
  [super init];
  dx = 1.0;
  dy = 0.0;
  dz = 0.0;

  N3D_CopyMatrix(N3DIdentityMatrix, myMatrix);
  myMatrix[0][3] = dx;
  myMatrix[1][3] = dy;
  myMatrix[2][3] = dz;

  return self;
}

- awake
{
  [super awake];
  N3D_CopyMatrix(N3DIdentityMatrix, myMatrix);
  myMatrix[3][0] = dx;
  myMatrix[3][1] = dy;
  myMatrix[3][2] = dz;

  return self;
}

- setDX:(RtFloat)newDX dy:(RtFloat)newDY dz:(RtFloat)newDZ
{
  dx = newDX;
  dy = newDY;
  dz = newDZ;

  N3D_CopyMatrix(N3DIdentityMatrix, myMatrix);
  myMatrix[3][0] = dx;
  myMatrix[3][1] = dy;
  myMatrix[3][2] = dz;

  return self;
}

- getDX:(RtFloat *)dxPtr dy:(RtFloat *)dyPtr dz:(RtFloat *)dzPtr
{
  *dxPtr = dx;
  *dyPtr = dy;
  *dzPtr = dz;

  return self;
}

- (BOOL)isLerpable { return YES; }

// note: because we've made the WWSampleList "safe" for having
// multiple samples with the same data, it's perfectly valid to return
// yourself or b
- lerpWith:b by:(float)uValue
{
   id      newMe = nil;
  RtFloat  dxA, dyA, dzA;
  RtFloat  dxB, dyB, dzB;

   if (([self class] != [b class]) || (uValue <= 0.0))
   {  return self;
   }

   if (uValue >= 1.0)
   {  return b;
   }

   newMe = [super lerpWith:b by:uValue]; // this makes a copy for us

   // okay, now do the specific stuff for this class
   [self getDX:&dxA dy:&dyA dz:&dzA];
   [b getDX:&dxB dy:&dyB dz:&dzB];
   [newMe setDX:(dxA + ((dxB - dxA) * uValue))
             dy:(dyA + ((dyB - dyA) * uValue))
             dz:(dzA + ((dzB - dzA) * uValue))];

   return newMe;
}

- lerpSelfWith:b by:(float)uValue
{
  RtFloat  dxA, dyA, dzA;
  RtFloat  dxB, dyB, dzB;

   if (([self class] != [b class]) || (uValue <= 0.0))
   {  return self;
   }

   if (uValue >= 1.0)
   {  return b;
   }

   [super lerpSelfWith:b by:uValue]; // this makes a copy for us

   // okay, now do the specific stuff for this class
   [self getDX:&dxA dy:&dyA dz:&dzA];
   [b getDX:&dxB dy:&dyB dz:&dzB];
   [self setDX:(dxA + ((dxB - dxA) * uValue))
            dy:(dyA + ((dyB - dyA) * uValue))
            dz:(dzA + ((dzB - dzA) * uValue))];

   return self;
}



- (BOOL)isMoot
{
  if (!dx && !dy && !dz)  {  return YES; }
  return NO;
}

- (BOOL)theSameAs:otherRIBCommand
{
  RtFloat  theDX, theDY, theDZ;


  [otherRIBCommand getDX:&theDX dy:&theDY dz:&theDZ];
  if (dx != theDX)
  {  return NO;
  }
  if (dy != theDY)
  {  return NO;
  }
  if (dz != theDZ)
  {  return NO;
  }

  return [super theSameAs:otherRIBCommand];
}



- renderSelf:(WW3DCamera *)camera  startingAt:(RtFloat)shutterOpenTime endingAt:(RtFloat)shutterCloseTime
{
  //[myShape logTransformWithMsg:"RiTranslate renderSelf: before"];
  RiTranslate(dx, dy, dz);
  //[myShape logTransformWithMsg:"RiTranslate renderSelf: after"];

  return self;
}

- transformCTM:(WW3DAttributeState *)attributeState startingAt:(RtFloat)shutterOpenTime endingAt:(RtFloat)shutterCloseTime
{ 
  RtMatrix  aMatrix, tmpMatrix;

  //[myShape logTransformWithMsg:"RiTranslate transformCTM before"];

  [attributeState getTransformMatrix:aMatrix];
  N3DMultiplyMatrix(myMatrix, aMatrix, tmpMatrix);
  [attributeState setTransformMatrix:tmpMatrix];

  //[myShape logTransformWithMsg:"RiTranslate transformCTM after"];

  //NXLogError("RIBTranslate myMatrix (-transformCTM:startingAt:endingAt):\n");
  //NXLogError("\t%f %f %f %f\n",  myMatrix[0][0], myMatrix[0][1], myMatrix[0][2], myMatrix[0][3]);
  //NXLogError("\t%f %f %f %f\n",  myMatrix[1][0], myMatrix[1][1], myMatrix[1][2], myMatrix[1][3]);
  //NXLogError("\t%f %f %f %f\n",  myMatrix[2][0], myMatrix[2][1], myMatrix[2][2], myMatrix[2][3]);
  //NXLogError("\t%f %f %f %f\n", myMatrix[3][0], myMatrix[3][1], myMatrix[3][2], myMatrix[3][3]);
  //NXLogError("RIBTranslate aMatrix (-transformCTM:startingAt:endingAt):\n");
  //NXLogError("\t%f %f %f %f\n",  aMatrix[0][0], aMatrix[0][1], aMatrix[0][2], aMatrix[0][3]);
  //NXLogError("\t%f %f %f %f\n",  aMatrix[1][0], aMatrix[1][1], aMatrix[1][2], aMatrix[1][3]);
  //NXLogError("\t%f %f %f %f\n",  aMatrix[2][0], aMatrix[2][1], aMatrix[2][2], aMatrix[2][3]);
  //NXLogError("\t%f %f %f %f\n", aMatrix[3][0], aMatrix[3][1], aMatrix[3][2], aMatrix[3][3]);

  return self; 
}

- (BOOL)isMotionBlurrable { return YES; }

- writeEve:(NXStream *)stream atTabLevel:(int)tab
{
   int  i;


   for (i = 0; i < tab; i++)
   {  NXPrintf(stream, "\t");
   }
   NXPrintf(stream, "Translate %f %f %f;", dx, dy, dz); 
   return self;
}

- writeInventorAtTime:(float)currentTime to:(NXStream *)stream atTabLevel:(int)tab
{
   int  i;


   for (i = 0; i < tab; i++)
   {  NXPrintf(stream, "\t");
   }
   NXPrintf(stream, "Translation {\n");
   for (i = 0; i < (tab+1); i++)
   {  NXPrintf(stream, "\t");
   }
   NXPrintf(stream, "translation %f %f %f\n", dx, dy, dz);
   for (i = 0; i < tab; i++)
   {  NXPrintf(stream, "\t");
   }
   NXPrintf(stream, "}");

   return self;

}

#define typeVector "fff"
#define typeValues &dx, &dy, &dz

- read:(NXTypedStream*)stream 
{
    int version;
    [super read:stream];

NX_DURING
    version = NXTypedStreamClassVersion(stream,"RIBTranslate");
    if (version == 0) NXReadTypes(stream,"i",&version), version=1;
    if (version == 1)
    {  NXReadTypes(stream, typeVector, typeValues);
    } 
NX_HANDLER
   NXLogError("in read: %s, exception [%d] raised.\n", 
                 [[self class] name], NXLocalHandler.code);
   return nil;
NX_ENDHANDLER
    return self;
}

- write:(NXTypedStream*)stream 
{
    [super write:stream];

    NXWriteTypes(stream,typeVector, typeValues);

    return self;
}

@end
